#include "UtilMemory.h"
#include <memory.h>
namespace Galaxy
{
	const uint32 c_uFixedSize=0x10;
	struct MemHead
	{
		uint32 iType;
		MemHead * pNext;
		inline void * Data()
		{ 
			return (void*)(((uint8*)this)+sizeof(MemHead));
		}
		static MemHead* FromData(void * pData)
		{
			return (MemHead*)(((uint8*)pData)-sizeof(MemHead));
		}
	};

	template<uint32 iMemSize>
	struct MemRecord
	{
		MemHead m_memHead;
		uint8 m_data[iMemSize];
	};

	class CAllocatorBase
	{
	public:
		CAllocatorBase()
			:m_pListHead(NULL)
			,m_pListTail(NULL)

		{

		}
		virtual ~CAllocatorBase(){};
		inline MemHead * Allocate()
		{
			//tbb::mutex::scoped_lock lock( m_MemLock );
			//boost::mutex::scoped_lock lock(m_MemLock);
			if(NULL==m_pListHead) Extend();

			MemHead * pRet=m_pListHead;

			m_pListHead=m_pListHead->pNext;

			if(pRet==m_pListTail) m_pListTail=NULL;

			return pRet;
		}
		inline void Free(MemHead * pMem)
		{
			pMem->pNext=NULL;

			//tbb::mutex::scoped_lock lock( m_MemLock );
			//boost::mutex::scoped_lock lock(m_MemLock);

			if(NULL!=m_pListTail) m_pListTail->pNext=pMem;

			m_pListTail=pMem;
			if(NULL==m_pListHead) m_pListHead=pMem;
		}

		virtual void Extend()=0;
		inline uint32  GetType()	{	return m_iType;}
		inline uint32  GetMemSize(){	return m_iMemSize;}
	protected:
		MemHead* m_pListHead;
		MemHead* m_pListTail;
		uint32		m_iType;
		uint32		m_iMemSize;
		//tbb::mutex  m_MemLock;
		//boost::mutex  m_MemLock;
	};

	template<uint32 iMemSize>
	class CFixSizeAllocator:public CAllocatorBase
	{
	public:
		CFixSizeAllocator()
		{
			m_iMemSize=iMemSize;

			m_iType=0;
			while(c_uFixedSize<<m_iType <iMemSize) m_iType++;

			m_pListHead=m_pListTail=NULL;

			if(m_iMemSize>=1024*c_uFixedSize)
				m_iExtendBlockCount=1;
			else
				m_iExtendBlockCount=1024*c_uFixedSize / m_iMemSize;
		}

		virtual void Extend()
		{
			MemRecord<iMemSize> * pBlock = new MemRecord<iMemSize>[m_iExtendBlockCount];

			MemRecord<iMemSize> *pTail=&pBlock[0];
			pTail->m_memHead.iType=m_iType;
			pTail->m_memHead.pNext=m_pListHead;

			for(uint32 ii=1;ii<m_iExtendBlockCount;ii++)
			{
				MemRecord<iMemSize> * pRecord=&pBlock[ii];
				pRecord->m_memHead.iType=m_iType;
				pRecord->m_memHead.pNext=&(pTail->m_memHead);
				pTail = pRecord;
			}

			m_pListHead= &(pTail->m_memHead);

			if(NULL==m_pListTail)
			{
				m_pListTail=&(pBlock[0].m_memHead);
			}

		}

	private:
		uint32 m_iExtendBlockCount;

	};

	CAllocatorBase * g_Allocators[32];
	class CAllocatorInitializer
	{
	public:
		CAllocatorInitializer()
		{
			CAllocatorBase * pAllocator=NULL;
			pAllocator=new CFixSizeAllocator<0x10>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x20>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x40>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x80>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x100>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x200>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x400>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x800>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x1000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x2000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x4000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x8000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x10000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x20000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x40000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x80000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x100000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x200000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x400000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x800000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x1000000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x2000000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x4000000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x8000000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x10000000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x20000000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

			pAllocator=new CFixSizeAllocator<0x40000000>();
			g_Allocators[pAllocator->GetType()]=pAllocator;

		}
	}__callocatorinitializer;

	
	void * ARealloc(void * pData,uint32 iNewSize)
	{
		MemHead* pMemHead=NULL;
		if(NULL!=pData)
		{
			MemHead*pMemHead=MemHead::FromData(pData);
			if(iNewSize<=(uint32)(c_uFixedSize<<(pMemHead->iType))) return pData;

			uint32 iNewType=pMemHead->iType;
			while((uint32)(c_uFixedSize<<iNewType) <iNewSize) iNewType++;

			CAllocatorBase * pNewAllocator=g_Allocators[iNewType];
			MemHead* pNewMemHead=pNewAllocator->Allocate();

			memcpy( pNewMemHead->Data(), pMemHead->Data(), (uint32)(c_uFixedSize<<pMemHead->iType));

			AFree(pData);

			return  pNewMemHead->Data();
		}
		else
		{
			uint32 iNewType=0;
			while((uint32)(c_uFixedSize << iNewType) <iNewSize) iNewType++;
			CAllocatorBase * pNewAllocator=g_Allocators[iNewType];
			MemHead* pNewMemHead=pNewAllocator->Allocate();
			return  pNewMemHead->Data();

		}
	}
	void  AFree(void * pData)
	{
		if(NULL==pData) return;
		MemHead* pMemHead=MemHead::FromData(pData);
		CAllocatorBase * pAllocator=g_Allocators[pMemHead->iType];
		pAllocator->Free(pMemHead);
	}
}